#include "bsp_bootloader.h"
#include "IAP.h"
#include <stdio.h>
#include "xmodem1k.h"



#define MAX_STRING_SIZE		50
#define iap_flag_addr		0x00004000	//保存更新标志位的扇区的起始地址
static uint8_t string[3][MAX_STRING_SIZE];
// ;LDR SP, [R0]		;Load new stack pointer address
//  ; LDR PC, [R0, #4]	;Load new program counter address
//通过汇编跳转
__asm void JMP_Boot( uint32_t address )
{
	ldr r0, =0x005000
	ldr r0, [r0]
	mov sp, r0
	ldr r0, =0x005004
	ldr r0, [r0]
    BX  r0
}
//跳转到APP
void Boot( void )
{
	SCB->VTOR = IMG_START_SECTOR & 0x3FFFFF80;	//修改中断向量表
	JMP_Boot(IMG_START_SECTOR);
}

//供更新程序使用的写入flash
uint32_t load_image(uint8_t *data, uint16_t length)
{
	uint8_t flag = 0;
	if(length > 0)
	{
		/*	准备写扇区操作 */
		flag = u32IAP_PrepareSectors(IMG_START_PAGE, IMG_END_PAGE);
		if(flag == IAP_STA_CMD_SUCCESS)
		{
			/*	将RAM内容复制到Flash IMG_START_SECTOR + received_data*/
			flag = u32IAP_CopyRAMToFlash(IMG_START_SECTOR + received_data, (uint32_t)data, length);
			if(flag == IAP_STA_CMD_SUCCESS)
			{				
				/*	比较复制内容 IMG_START_SECTOR + received_data*/
				flag = u32IAP_Compare(IMG_START_SECTOR + received_data, (uint32_t)data, length, 0);
				if(flag == IAP_STA_CMD_SUCCESS)
				{
					received_data +=  length;
					return 1;
				}
			}
		}
		return 0;
	}
	else
		return 0;
}
//写一页数据到flash中
uint32_t write_page(uint32_t page,uint8_t *data, uint16_t length)
{
	uint8_t flag = 0;
	if(length > 0)
	{
		/*	准备写扇区操作 */
		flag = u32IAP_PrepareSectors(page, page);
		if(flag == IAP_STA_CMD_SUCCESS)
		{
			/*	将RAM内容复制到Flash IMG_START_SECTOR + received_data*/
			flag = u32IAP_CopyRAMToFlash(iap_flag_addr, (uint32_t)data, length);
			if(flag == IAP_STA_CMD_SUCCESS)
			{				
				/*	比较复制内容 IMG_START_SECTOR + received_data*/
				flag = u32IAP_Compare(iap_flag_addr, (uint32_t)data, length, 0);
				if(flag == IAP_STA_CMD_SUCCESS)
				{
					return 1;
				}
			}
		}
		return 0;
	}
	else
		return 0;
}
//获取iap的相关信息
void get_info(void)
{
	uint32_t ints[4];
	/*	显示引导程序版本 */
	if(u32IAP_ReadBootVersion (&ints[0], &ints[1]) == IAP_STA_CMD_SUCCESS)
	{
		snprintf((char *)string[0], MAX_STRING_SIZE, "Boot Code version %d.%d", ints[0], ints[1]); 
	}
	
	/*	显示器件ID */
	if(u32IAP_ReadPartID(&ints[0]) == IAP_STA_CMD_SUCCESS)
	{
		snprintf((char *)string[1], MAX_STRING_SIZE, "Part ID: %d (%#x)", ints[0], ints[0]); 
	}
	
	/*	显示器件序列号 */
	u32IAP_ReadSerialNumber(&ints[0], &ints[1], &ints[2], &ints[3]);
	snprintf((char *)string[2], MAX_STRING_SIZE, "Serial #: %08X:%08X:%08X:%08X", ints[0], ints[1], ints[2], ints[3]);
								
}
//擦除选中的页面，起始地址与终止地址
void erase_fun(uint32_t start_page,uint32_t end_page)
{
	/*	擦除存储区准备IAP升级  */
	if ((u32IAP_PrepareSectors(start_page, end_page) == IAP_STA_CMD_SUCCESS)&&\
		(u32IAP_EraseSectors  (start_page, end_page) == IAP_STA_CMD_SUCCESS))
	{
		;
	}
}
//更新程序，内部采用的xmodem协议
void update(void)
{
	/* 更新APP程序 */
	vXmodem1k_Client(&load_image);
}
//写入更新或者跳转APP的标志位
uint8_t iap_write_update_flag(uint8_t value)
{
	uint32_t i = 0;
	uint8_t *p;
	p = (uint8_t*)0x00004000;//第四扇区地址
	//首先要将第四扇区的数据全部读取到ram里面
	for(i = 0; i < 4096; i++)
	{
		read_buf[i] = *p;
		p++;
	}
	//然后检查最后一个数据和我们要设置的数据是否相等
	if(read_buf[4095] == value)//相等,不用设置了
	{
		return 1;
	}
	else
	{
		//不等,先擦除第4扇区
		erase_fun(4,4);
		//将数组最后一个元素设置为指定值
		read_buf[4095] = value;
		return write_page(4,read_buf,4096);
	}
}
